///\todo upgrade

//////////////////////////////////////////////////////////////////////////////////
//                                                                              //
//  This file is part of the buola project (https://code.google.com/p/buola/).  //
//                                                                              //
//  Copyright(c) 2007-2012 Xavi Gratal                                          //
//  gratal AT gmail DOT com                                                     //
//                                                                              //
//  Buola is free software: you can redistribute it and/or modify               //
//  it under the terms of the GNU General Public License as published by        //
//  the Free Software Foundation, either version 3 of the License, or           //
//  (at your option) any later version.                                         //
//                                                                              //
//  Buola is distributed in the hope that it will be useful,                    //
//  but WITHOUT ANY WARRANTY; without even the implied warranty of              //
//  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the               //
//  GNU General Public License for more details.                                //
//                                                                              //
//  You should have received a copy of the GNU General Public License           //
//  along with buola.  If not, see <http://www.gnu.org/licenses/>.              //
//                                                                              //
//////////////////////////////////////////////////////////////////////////////////

#ifndef _CPYRAMID_H_
#define _CPYRAMID_H_

#include <buola/image.h>
#include <buola/image/algorithm/transform.h>

namespace buola { namespace img {

template<typename tImage>
class CPyramid
{
    typedef CView<typename tImage::TFormat> tView;
    typedef CMView<typename tImage::TFormat> tMView;
public:
    CPyramid()
    {}

    CPyramid(const CSize_i &pSize,int pNLevels)
    {
        Recreate(pSize,pNLevels);
    }

    CPyramid(const tView &pSrc,int pNLevels)
    {
        Recreate(pSrc,pNLevels);
    }

    void clear()
    {
        mLevels.clear();
    }

    void Recreate(const CSize_i &pSize,int pNLevels)
    {
        assert(pNLevels>0);

        if(mLevels.size()==pNLevels&&Width()==pSize.x&&Height()==pSize.y)
            return;

        mLevels.clear();

        CSize_i lSize(pSize);
        
        for(int i=0;i<pNLevels;i++)
        {
            mLevels.emplace_back(new tImage(lSize));

            lSize.x>>=1;
            lSize.y>>=1;
        }
    }

    void Recreate(const tView &pSrc,int pNLevels)
    {
        CSize_i lSize(pSrc.Width(),pSrc.Height());
        Recreate(lSize,pNLevels);

        copy_pixels(pSrc,*mLevels[0]);
        
        for(int i=1;i<pNLevels;i++)
        {
            const tView &lPrevious=*mLevels[i-1];
            const tMView &lCurrent=*mLevels[i];

            if(lPrevious.Width()==2*lCurrent.Width()&&lPrevious.Height()==2*lCurrent.Height())
            {
                pyr_down(lPrevious,lCurrent);
            }
            else
            {
                resize(lPrevious,lCurrent);
            }
        }
    }

    void push_back(tImage *pImage)
    {
        mLevels.emplace_back(pImage);
    }

    int Width()                     {   return mLevels[0]->Width();  }
    int Height()                    {   return mLevels[0]->Height(); }
    std::size_t NumLevels()         {   return mLevels.size();      }
    const tView &operator()(int i) const   {   return *mLevels[i];          }
    const tMView &operator()(int i)        {   return *mLevels[i];          }

private:
    std::vector<std::unique_ptr<tImage>> mLevels;
};

/*namespace img*/ } /*namespace buola*/ }

#endif
